package com.example.springbootdemo.aop;

import com.example.springbootdemo.interface1.LimitType;
import com.example.springbootdemo.interface1.Limiting;
import com.example.springbootdemo.util.ApplicationContextUtil;
import com.example.springbootdemo.util.RedisSonUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RateType;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * @author 84246
 */
@Slf4j
@Component
@Aspect
public class LimiterAspect {

    @Before("@annotation(limiting)")
    public void before(JoinPoint joinPoint, Limiting limiting) {
        log.info("before start");
        int count = limiting.count();
        int time = limiting.time();
        log.info("count:{},time:{}", count, time);

        String key = getKey(joinPoint, limiting);

        // 确定速率
        RateType rateType = RateType.OVERALL;
        if (LimitType.CLUSTER.equals(limiting.limitType())) {
            rateType = RateType.PER_CLIENT;
        }
        LimiterAspect bean = ApplicationContextUtil.getBean(LimiterAspect.class);
        // 调用RedisSonUtils.rateLimiter方法进行限流处理
        long number = RedisSonUtils.rateLimiter(key, count, time, rateType);
        if (number == -1) {
            throw new RuntimeException("限流");
        }
        log.info("before end");
    }

    private String getKey(JoinPoint joinPoint, Limiting limiting) {
        String key = limiting.key();
        if (LimitType.IP.equals(limiting.limitType())) {
            // 根据ip限流
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest();
            String ip = request.getRemoteAddr();

            key = key + "_" + ip;
        } else if (LimitType.CLUSTER.equals(limiting.limitType())) {
            // 根据集群限流
            // 1.获取集群ID

            // 2.拼接key
        } else {
            // 全局限流
            // 1.通过反射获取method
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            log.info("method:{}", method.getName());

            Class<?> declaringClass = method.getDeclaringClass();
            log.info("declaringClass:{}", declaringClass);
            key = key + "_" + declaringClass.getName() + "_" + method.getName();
        }

        log.info("key :{}", key);
        return key;
    }

    public static String getIpAddress(HttpServletRequest request) {
        String[] headersToCheck = {"X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP"};

        for (String header : headersToCheck) {
            String ipAddress = request.getHeader(header);

            if (ipAddress != null && !ipAddress.isEmpty() && !"unknown".equalsIgnoreCase(ipAddress)) {
                // Extract the first IP address from the comma-separated list if multiple addresses are present
                if (ipAddress.contains(",")) {
                    return ipAddress.split(",")[0].trim();
                } else {
                    return ipAddress.trim();
                }
            }
        }

        // If no valid IP found in headers, fallback to the default method
        return request.getRemoteAddr();
    }

}
